package NG::Chat::Client::Sock;
use strict;
use warnings;

use EV;
use NG::Sys::Sock qw(
InetConnect SendMessage WaitMessage
WaitMessagePrepared PrepareWaitMessage
SendMessagePrepared PrepareSendMessage
);
use NG::Chat::Client::Message qw(SockRequest SockParse);

sub Create {
	my $app = shift;
	my %http = (
		addr => [$app->{'sock-connect'}{peer},$app->{'sock-connect'}{port},1],
		rid => 0,
		sid => "",
		chanel => "",
		keep_alive => $app->{keep_alive},
	);
	my $self = bless \%http,__PACKAGE__;
	
	return $self;
}
sub responser{
	my $self = shift;
	my $responser = shift;
	$self->{responser} = $responser;
}
sub cleanup {
	my $self = shift;
	delete $self->{sock};
	delete $self->{sender};
	delete $self->{reader};
	delete $self->{keeper};
	delete $self->{responser};
	delete $self->{prepared_sender};
}
sub send_message {
	my $self = shift;
	my $msg = shift;
	my $to_send = SockRequest($self,$msg);
	my $sock;
	unless($sock = $self->{sock}){
		$sock = $self->{sock} = InetConnect(@{$self->{addr}});
		unless($sock){
			return {error=>10,text=>"connect '$@'"};
		}
		delete $self->{sender};
	}
	my $sender;
	unless($sender = $self->{prepared_sender}){
		$sender = $self->{prepared_sender} = PrepareSendMessage(make_getClose($self),make_getDone($self));
	}
	unless($self->{sender}){
		$self->{sender} = SendMessagePrepared($sock,$to_send,$sender);
	}else{
		$self->{sender}->data->[0] .= $to_send;
	}
	return 0;
}
sub keepalive {
	my $self = shift;
	unless($self->{keeper}){
		$self->{keeper} = EV::timer $self->{keep_alive},$self->{keep_alive},
			sub {
				if($self->{sid}){
					send_message($self,{cmd=>"ping"});
				}
			};
	}else{
		$self->{keeper}->again;
	}
}
sub make_getClose {
	my $self = shift;
	return sub {
		my $w = shift;
		delete $self->{sock};
		delete $self->{sender};
		delete $self->{reader};
	};
}
sub make_getMessage {
	my $self = shift;
	return sub {
		my ($w,$msg) = @_;
		if($self->{responser}->($self,$msg)){
			send_message($self,{cmd=>"check"});
			$self->keepalive;
		}
	};
}
sub make_getDone {
	my $self = shift;
	my $reader = PrepareWaitMessage(\&SockParse,make_getMessage($self),make_getClose($self));
	return sub {
		my $w = shift;
		delete $self->{sender};
		unless($self->{reader}){
			$self->{reader} = WaitMessagePrepared($w->fh,$reader);
		}
	};
}

1;
